<!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  
  
  
  <link rel="shortcut icon" href="../../img/favicon.ico">
  <title>Porting - COROS Documentation</title>
  <link rel="stylesheet" href="../../css/theme.css" />
  <link rel="stylesheet" href="../../css/theme_extra.css" />
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/github.min.css" />
  
  <script>
    // Current page data
    var mkdocs_page_name = "Porting";
    var mkdocs_page_input_path = "architecture/03_porting.md";
    var mkdocs_page_url = null;
  </script>
  
  <script src="../../js/jquery-2.1.1.min.js" defer></script>
  <script src="../../js/modernizr-2.8.3.min.js" defer></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
  <script>hljs.initHighlightingOnLoad();</script> 
  
</head>

<body class="wy-body-for-nav" role="document">

  <div class="wy-grid-for-nav">

    
    <nav data-toggle="wy-nav-shift" class="wy-nav-side stickynav">
    <div class="wy-side-scroll">
      <div class="wy-side-nav-search">
        <a href="../.." class="icon icon-home"> COROS Documentation</a>
        <div role="search">
  <form id ="rtd-search-form" class="wy-form" action="../../search.html" method="get">
    <input type="text" name="q" placeholder="Search docs" title="Type search term here" />
  </form>
</div>
      </div>

      <div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
                <ul>
                    <li class="toctree-l1"><a class="reference internal" href="../..">Home</a>
                    </li>
                </ul>
                <p class="caption"><span class="caption-text">About</span></p>
                <ul>
                    <li class="toctree-l1"><a class="reference internal" href="../../COPYRIGHT/">Copyright</a>
                    </li>
                    <li class="toctree-l1"><a class="reference internal" href="../../LICENSE/">License</a>
                    </li>
                </ul>
                <p class="caption"><span class="caption-text">The Beginner's Guide to:</span></p>
                <ul>
                    <li class="toctree-l1"><a class="reference internal" href="../../tutorials/01_getting_started/">Getting Started</a>
                    </li>
                </ul>
                <p class="caption"><span class="caption-text">The Hitchker's Guide to:</span></p>
                <ul>
                    <li class="toctree-l1"><a class="reference internal" href="../../guides/01_coroutines/">Coroutines</a>
                    </li>
                    <li class="toctree-l1"><a class="reference internal" href="../../guides/02_event_queues/">Event Queues</a>
                    </li>
                    <li class="toctree-l1"><a class="reference internal" href="../../guides/03_components/">Components</a>
                    </li>
                </ul>
                <p class="caption"><span class="caption-text">The Technocrat's Guide to:</span></p>
                <ul>
                    <li class="toctree-l1"><a class="reference internal" href="../../reference/01_co/">co.h</a>
                    </li>
                    <li class="toctree-l1"><a class="reference internal" href="../../reference/02_evq/">evq.h</a>
                    </li>
                    <li class="toctree-l1"><a class="reference internal" href="../../reference/03_comp/">comp.h</a>
                    </li>
                </ul>
                <p class="caption"><span class="caption-text">The Technomancer's Guide to:</span></p>
                <ul class="current">
                    <li class="toctree-l1"><a class="reference internal" href="../01_coroutines/">Coroutines</a>
                    </li>
                    <li class="toctree-l1"><a class="reference internal" href="../02_event_queues/">Event Queues</a>
                    </li>
                    <li class="toctree-l1 current"><a class="reference internal current" href="./">Porting</a>
    <ul class="current">
    <li class="toctree-l2"><a class="reference internal" href="#coroutines">Coroutines</a>
        <ul>
    <li class="toctree-l3"><a class="reference internal" href="#co_init_impl">co_init_impl()</a>
    </li>
    <li class="toctree-l3"><a class="reference internal" href="#co_prologue_impl">co_prologue_impl()</a>
    </li>
    <li class="toctree-l3"><a class="reference internal" href="#co_yield_impl">co_yield_impl()</a>
    </li>
    <li class="toctree-l3"><a class="reference internal" href="#porting-these-functions">Porting these functions.</a>
    </li>
        </ul>
    </li>
    </ul>
                    </li>
                </ul>
      </div>
    </div>
    </nav>

    <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">

      
      <nav class="wy-nav-top" role="navigation" aria-label="top navigation">
        <i data-toggle="wy-nav-top" class="fa fa-bars"></i>
        <a href="../..">COROS Documentation</a>
      </nav>

      
      <div class="wy-nav-content">
        <div class="rst-content">
          <div role="navigation" aria-label="breadcrumbs navigation">
  <ul class="wy-breadcrumbs">
    <li><a href="../..">Docs</a> &raquo;</li>
    
      
        
          <li>The Technomancer's Guide to: &raquo;</li>
        
      
    
    <li>Porting</li>
    <li class="wy-breadcrumbs-aside">
      
    </li>
  </ul>
  
  <hr/>
</div>
          <div role="main">
            <div class="section">
              
                <h1 id="the-technomancers-guide-to-porting-coros">The Technomancer's Guide to Porting COROS</h1>
<p>This document provides detailed technical information required to port COROS to other architectures.  It is recommended that "<a href="../01_coroutines/">The Technomancer's Guide to Coroutines</a>" be read first to understand some of the contents of this document and, specifically, their place in the overall architecture.</p>
<p>When porting COROS, the only issue that needs to be dealt with is coroutines.  These have hardware-specific operations which cannot be done in pure C.</p>
<h2 id="coroutines">Coroutines</h2>
<p>Porting COROS' coroutine engine to a new core involves replacing one file with three functions.  The files for these are contained in subdirectories underneath src.  For example:</p>
<pre><code>.
|
+- src
   |
   +- compressed
   |
   +- thumb
</code></pre>
<p>In this example, the <code>compressed</code> directory contains the RISC-V compressed ISA port (<code>co_impl_riscv_compressed_gcc.c</code>) while the <code>thumb</code> directory contains the ARM Thumb ISA port (<code>co_impl_arm_thumb_gcc.c</code> and <code>co_impl_arm_thumb_iar.c</code>).  In general the naming convention is: <code>co_impl_&lt;core&gt;_&lt;subset&gt;_&lt;compiler&gt;.c</code>.  Introducing a new architecture involves making a new subdirectory with a shorthand name, copying any of the other <code>co_impl_*.c</code> files into it, named reasonably, and then porting the functions within to the new architecture.</p>
<h3 id="co_init_impl"><code>co_init_impl()</code></h3>
<p>The ARM/Thumb/GCC implementation of this function is this:</p>
<pre><code class="language-C">#define SET_STACK_VAL(OFFSET, VALUE) (stack_buffer[stack_buffer_count - (OFFSET)] = VALUE)

void co_init_impl(stack_t **stack_pointer, stack_t **stack_canary, co_function co_cb,
                  stack_t *stack_buffer, size_t stack_buffer_count)
{
    // check that stack is aligned
    assert((uintptr_t)stack_buffer % 4 == 0);

    // setup stack
    SET_STACK_VAL(1, (uintptr_t)co_prologue_impl); // return to platform prologue
    SET_STACK_VAL(2, 0);                           // r7
    SET_STACK_VAL(3, (uintptr_t)co_halt_impl);     // r6
    SET_STACK_VAL(4, 0xffffffff);                  // r5
    SET_STACK_VAL(5, (uintptr_t)co_cb);            // r4
    SET_STACK_VAL(6, 0);                           // r11
    SET_STACK_VAL(7, 0);                           // r10
    SET_STACK_VAL(8, 0);                           // r9
    SET_STACK_VAL(9, 0);                           // r8

    // setup stack pointer and canary
    *stack_pointer = &amp;stack_buffer[stack_buffer_count - 9];
    *stack_canary = stack_buffer;
}
</code></pre>
<p>This function, called by <code>co_create()</code> sets up a fake stack frame for a newly-created coroutine.  This way when <code>co_resume()</code> is called there is already a "running coroutine" in place and instead of having to contend with coroutine states (uninitialized/running/halted) and instead a yield operation is performed.  At the absolute end of the stack it supplies the "return" address, which in this case is the <code>co_prologue_impl()</code> function supplied in this file as well.  It then also supplies the "callee-saved" register values for <code>r4</code>-<code>r11</code>.  In the <code>r4</code> position it places the coroutine's implementation function callback, the <code>r5</code> position contains a dummy value (reserved for possible future expansion), and in the <code>r6</code> position it places the address of the coroutine halting function.  (<code>co_halt_impl()</code> is implemented entirely in C and is thus not part of porting.)  Remaining registers are left as 0 by convention.</p>
<p>The order of stored values is important because of how they are pushed and popped while yielding; this function must match <code>co_yield_impl()</code>'s implementation.</p>
<h3 id="co_prologue_impl"><code>co_prologue_impl()</code></h3>
<p>The prologue code is a small snippet of code that is run <em>once</em> when <code>co_resume()</code> first runs a coroutine.  The ARM/Thumb/GCC implementation is this:</p>
<pre><code class="language-C">__attribute__((naked)) void co_prologue_impl(void)
{
    __asm volatile(
        &quot;    mov lr, r6 \n&quot; // set lr to point to co_halt_impl
        &quot;    bx r4      \n&quot;
    );
}
</code></pre>
<p>This very simple prologue only sets up <code>co_halt_impl()</code> as the "return" address should the coroutine callback exit and then does a straight branch to the callback inside <code>r4</code> (initialized into that spot by <code>co_init_impl()</code> above).</p>
<h3 id="co_yield_impl"><code>co_yield_impl()</code></h3>
<p>The real meat of the coroutine is the stack swap of yielding.  The ARM/Thumb/GCC implementation is this:</p>
<pre><code class="language-C">__attribute__((naked)) void *co_yield_impl(stack_t **stack_pointer, void *data)
{
    UNUSED(stack_pointer);
    UNUSED(data);
    __asm volatile(
        &quot;    push {r4,r5,r6,r7,lr} \n&quot; // push callee saved registers
        &quot;    mov r4, r8            \n&quot; // yes we need these moves, thumb1 can
        &quot;    mov r5, r9            \n&quot; // only push r0-r7 at the same time
        &quot;    mov r6, r10           \n&quot;
        &quot;    mov r7, r11           \n&quot;
        &quot;    push {r4,r5,r6,r7}    \n&quot;
        &quot;    mov r2, sp            \n&quot; // swap stack, takes several instructions
        &quot;    ldr r3, [r0]          \n&quot; // here because thumb1 can't load/store sp
        &quot;    str r2, [r0]          \n&quot;
        &quot;    mov sp, r3            \n&quot;
        &quot;    mov r0, r1            \n&quot; // return arg
        &quot;    pop {r4,r5,r6,r7}     \n&quot; // pop callee saved registers and return
        &quot;    mov r8, r4            \n&quot;
        &quot;    mov r9, r5            \n&quot;
        &quot;    mov r10, r6           \n&quot;
        &quot;    mov r11, r7           \n&quot;
        &quot;    pop {r4,r5,r6,r7,pc}  \n&quot;
    );
    // We have done the return manually in assembler.
}
</code></pre>
<p>On entry, this function has a pointer to the stack block for the target coroutine in <code>r0</code> and the coroutine's data pointer in <code>r1</code>.  It is written for Thumb1 instructions for maximum portability (a Thumb2 version would be more elegant, but less portable).  As a result we manually push registers in stages.</p>
<p>The first stage pushes the <code>lr</code> (<code>r14</code>), then <code>r7</code> to <code>r4</code> in sequence.  Then a series of moves copies <code>r8</code>-<code>r11</code> into <code>r4</code>-<code>r7</code> and then pushes <code>r7</code> to <code>r4</code> in sequence again.  By the end of this stage, all of the callee-saved registers and the link register are on the stack.</p>
<p>In the second stage, we swap the stack.  Again, Thumb1 puts some limits on what we can do and we need several instructions in sequence to perform this, using up another (caller-saved) register for scratch.  As part of the stack swap we <em>also</em> deposit the data value parameter into the return value slow (<code>r1</code> -&gt; <code>r0</code>) because the data we pass in a yield is the <strong>return</strong> value of the place we're yielding to.</p>
<p>Finally, in the third stage, we reverse the pushes at the top and instead pop the register values from the new stack, popping the final value (the <code>lr</code> going in) into the <code>pc</code> instead, thus transitioning to where the routine last left off.</p>
<h3 id="porting-these-functions">Porting these functions.</h3>
<p>The functions involved here are very small and very simple.  Porting to another architecture involves looking at these implementations and matching them to the instruction set and ABI of the target environment.  The initialization routine needs to build up a fake stack with relevant values stored in the right places.  The prologue makes sure that should the coroutine callback actually return (instead of yielding) that it is handled in a safe way via <code>co_halt_impl()</code>.  And the yielding process does the stack shuffle and ensures that the passed-in data parameter is placed as the returned data post stack-swap.  Cues for how to do these can likely be found by looking into any RTOS of the conventional pre-emptive kind and ripping out the bits that fit to COROS' needs.  (This is, indeed, how this set of functions was first written, followed by some fine-tuning to eliminate the excess overhead that pre-emptive systems need to concern themselves with.)</p>
<p>When doing the port there are a set of issues which must be addressed before writing the code.  These are:</p>
<ul>
<li>Stack growth direction.  Most modern architectures are top-down.  Some, however, are bottom-up.  Be sure you're aware of which your target is.</li>
<li>Stack alignment requirements.  Stacks must be 32-bit aligned in ARM.  In other architectures these could be down to byte-alignment or even <strong>page</strong> alignment.  Be sure you are aware of what your core needs.</li>
<li>Callee-saved vs caller-saved registers.  This is critical to understand.  Your implementation of the stack swap <em>must</em> store/restore the callee-saved registers when swapping.  Consult both the core vendor's ABI and your compiler's documentation to know exactly what must be preserved.</li>
<li>Instruction set limitations.  There is a balancing act to be had between performance/elegance and capability.  A Thumb2 implementation of these functions would be shorter, easier to understand, and a little bit faster than the version provided here.  On the other hand it would not be available to several devices.  This implementation, on the other hand, is a fraction of a microsecond slower, a bit harder to read, but for that works with any Thumb-capable device, Thumb1 or Thumb2.  Decide your precise architecture target and be aware of what limitations this places on related cores before implementation.</li>
<li>Function call conventions.  Your core's vendor and/or your compiler documentation will tell you where arguments go, how to deal with arguments that don't fit in the default places provided, where return values go, and again how to deal with those return values which don't fit in that space.  Be aware of all of these and make sure your implementation conforms to these conventions.  Pay special attention to arguments and return values since one of the yielding arguments becomes a return value.</li>
</ul>
              
            </div>
          </div>
          <footer>
  
    <div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
      
      
        <a href="../02_event_queues/" class="btn btn-neutral" title="Event Queues"><span class="icon icon-circle-arrow-left"></span> Previous</a>
      
    </div>
  

  <hr/>

  <div role="contentinfo">
    <!-- Copyright etc -->
    
  </div>

  Built with <a href="https://www.mkdocs.org/">MkDocs</a> using a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
      
        </div>
      </div>

    </section>

  </div>

  <div class="rst-versions" role="note" aria-label="versions">
    <span class="rst-current-version" data-toggle="rst-current-version">
      
      
        <span><a href="../02_event_queues/" style="color: #fcfcfc;">&laquo; Previous</a></span>
      
      
    </span>
</div>
    <script>var base_url = '../..';</script>
    <script src="../../js/theme.js" defer></script>
      <script src="../../search/main.js" defer></script>
    <script defer>
        window.onload = function () {
            SphinxRtdTheme.Navigation.enable(true);
        };
    </script>

</body>
</html>
